上回我們接到了request但跳過了其中處理request的部分,而其中django在處理request的部分呢,就是middleware中間件,middleware會把收到的request處理後生成response,而middleware又有好幾個,他們是怎麼串連在一起的呢?具體又是怎麼做的呢?我們待會就來一探究竟~
我們先回到上次抓到middleware的地方!
其中會看到response = self._middleware_chain(request)
,這個middleware_chain怎麼形成的呢?來去看看~
點下去會看到是在BaseHandler
中的function load_middleware()
(太長了截圖不了,以下是他的原始碼
# BaseHandle
def load_middleware(self, is_async=False):
"""
Populate middleware lists from settings.MIDDLEWARE.
Must be called after the environment is fixed (see __call__ in subclasses).
"""
self._view_middleware = []
self._template_response_middleware = []
self._exception_middleware = []
get_response = self._get_response_async if is_async else self._get_response
handler = convert_exception_to_response(get_response)
handler_is_async = is_async
for middleware_path in reversed(settings.MIDDLEWARE):
middleware = import_string(middleware_path)
middleware_can_sync = getattr(middleware, "sync_capable", True)
middleware_can_async = getattr(middleware, "async_capable", False)
if not middleware_can_sync and not middleware_can_async:
raise RuntimeError(
"Middleware %s must have at least one of "
"sync_capable/async_capable set to True." % middleware_path
)
elif not handler_is_async and middleware_can_sync:
middleware_is_async = False
else:
middleware_is_async = middleware_can_async
try:
# Adapt handler, if needed.
adapted_handler = self.adapt_method_mode(
middleware_is_async,
handler,
handler_is_async,
debug=settings.DEBUG,
name="middleware %s" % middleware_path,
)
mw_instance = middleware(adapted_handler)
except MiddlewareNotUsed as exc:
if settings.DEBUG:
if str(exc):
logger.debug("MiddlewareNotUsed(%r): %s", middleware_path, exc)
else:
logger.debug("MiddlewareNotUsed: %r", middleware_path)
continue
else:
handler = adapted_handler
if mw_instance is None:
raise ImproperlyConfigured(
"Middleware factory %s returned None." % middleware_path
)
if hasattr(mw_instance, "process_view"):
self._view_middleware.insert(
0,
self.adapt_method_mode(is_async, mw_instance.process_view),
)
if hasattr(mw_instance, "process_template_response"):
self._template_response_middleware.append(
self.adapt_method_mode(
is_async, mw_instance.process_template_response
),
)
if hasattr(mw_instance, "process_exception"):
# The exception-handling stack is still always synchronous for
# now, so adapt that way.
self._exception_middleware.append(
self.adapt_method_mode(False, mw_instance.process_exception),
)
handler = convert_exception_to_response(mw_instance)
handler_is_async = middleware_is_async
# Adapt the top of the stack, if needed.
handler = self.adapt_method_mode(is_async, handler, handler_is_async)
# We only assign to this when initialization is complete as it is used
# as a flag for initialization being complete.
self._middleware_chain = handler
在最後一行可以看到我們的目標self._middleware_chain = handler
,在來回推看看這個handler怎麼形成的吧~
先把焦點移至上面
會看到他把self._get_response
丟進去一個function convert_exception_to_response()
裡面後指定給變數handler,我們先來看看生成handler的這支function
這個function其實看function name大概就可以猜測他想做什麼了,而看註解後就更詳細了~
我們也可以從程式碼中看到django會去處理sync or async,而預設是sync所以我們就看sync的部分就好了~
這個部分是python自己寫decorator的做法,因為我自己也沒什麼客製化寫過decorator所以看的時候花了一些時間去找出程式的流向!這邊可以看到他把傳進來的get_response
參數丟到inner裡面後去處理try catch吐出結果response,然而這些都會在實際那個self._middleware_chain
被call的時候才會觸發,這邊會拋出inner這個function出去到外面那個handler,說得有點抽象,畫個圖來看看~
應該還算清楚XD
那現在我們知道了handler會是一個inner function包含了處理request的邏輯,那我們繼續往下看那個for迴圈
可以看到他會去跑一遍settings.MIDDLEWARE
也就是這個,而且是反轉的(這邊之後再講)
把該middleware import進來後,會把原先的handler由self.adapt_method_mode()
去check並轉換sync or async,最後再把他丟進去前面import進來的middleware -> mw_instance = middleware(handler)
之後的過程處理一些middleware中的function(這邊我們也之後再說)
最後來到這裡,for loop的尾巴
又再把剛剛的import middleware丟給handler = convert_exception_to_response(mw_instance)
,那我們前面已經知道這個handler是一個inner function了,就這樣把for loop跑完後指定給self._middleware_chain
最後再來畫一張圖看看~
我們今天看了middleware_chain生成的過程,但跳過了兩個重要的地方
self._get_response
Middleware
這個class本身這兩個過明後天再來看看吧!!